﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using com.bodurov.NearestStarsVisualizerLinesIn3D;

namespace com.bodurov.NearestStarsVisualizer
{
    public partial class Page : UserControl, IVectorVisualizerUI
    {
        /// <summary>
        /// Used to slow down the movement
        /// </summary>
        private const double COEF_MOVE = 0.3;

        private static readonly Brush _AxisDefaultBrush = new SolidColorBrush(Color.FromArgb(0x99, 0xAA, 0xAA, 0xAA));
        private static readonly Brush _SubAxisDefaultBrush = new SolidColorBrush(Color.FromArgb(0x40, 0x70, 0x70, 0x70));
        private const double _AxisDefaultLength = 304.5;
        private static readonly Point _AxisDefaultCenter = new Point(422, 375);
        private const double _AxisArrowSize = 10.0;
        private const double _LetterShift = 5.0;
        private const double _LetterWidth = 10.0;
        private const double _LetterHeight = 20.0;
        private const double _VectorFactor = 17.0;
        private const double _VectorLimit = 17.0;



        private bool _isDragging;
        private bool _isOverSliderX;
        private bool _isOverSliderY;
        private bool _isOverSliderZ;
        private Point _mouseLastPoint;





        public Brush AxisBrush { get { return _AxisDefaultBrush; } }
        public Brush SubAxisBrush { get { return _SubAxisDefaultBrush; } }
        public double AxisLength { get { return _AxisDefaultLength; } }
        public Point AxisCenter { get { return _AxisDefaultCenter; } }
        public double AxisArrowSize { get { return _AxisArrowSize; } }
        public double LetterShift { get { return _LetterShift; } }
        public double LetterWidth { get { return _LetterWidth; } }
        public double LetterHeight { get { return _LetterHeight; } }
        public double VectorFactor { get { return _VectorFactor; } }
        public double VectorLimit { get { return _VectorLimit; } }
        public bool IsDragging { get { return _isDragging; } }

        public string CurrentPageUrl { get; set; }

        public VectorVisualizer Visualizer { get; internal set; }

        public static Page Current;
        

        public Page()
        {
            Current = this;

            InitializeComponent();

            this.Loaded += this.Page_Loaded;
            this.MouseLeftButtonDown += this.Page_MouseLeftButtonDown;
            this.MouseLeftButtonUp += this.Page_MouseLeftButtonUp;
            this.MouseLeave += this.Page_MouseLeave;
            this.MouseMove += this.Page_MouseMove;

            this.MouseWheel += this.Page_MouseWheel;
        }

        private void Page_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            var sign = e.Delta > 0 ? 1 : -1;
            e.Handled = true;
            this.Visualizer.Lines.DefaultZoom += 0.1 * sign;

            this.Visualizer.Lines.ReDraw();
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            this.Visualizer.Lines.ReDrawn += this.Lines_ReDrawn;
        }

        public void ConfigLoaded()
        {
            this.ProcessRunningSign.Visibility = Visibility.Collapsed;
            this.GraphContainer.Visibility = Visibility.Visible;
            this.ControlContainer.Visibility = Visibility.Visible;
            this.Visualizer.Initialize();
        }

        private void Lines_ReDrawn(object sender, EventArgs e)
        {
            if (!this._isOverSliderX) this.SliderX.Value = ((this.Visualizer.Lines.RotationDegreesX + 180) / 360D) * 10;
            if (!this._isOverSliderX) this.SliderX.Value = ((this.Visualizer.Lines.RotationDegreesX + 180) / 360D) * 10;
            if (!this._isOverSliderY) this.SliderY.Value = ((this.Visualizer.Lines.RotationDegreesY + 180) / 360D) * 10;
            if (!this._isOverSliderZ) this.SliderZ.Value = ((this.Visualizer.Lines.RotationDegreesZ + 180) / 360D) * 10;

            this.DegreesX.Text = this.Visualizer.Lines.RotationDegreesX.ToString();
            this.DegreesY.Text = this.Visualizer.Lines.RotationDegreesY.ToString();
            this.DegreesZ.Text = this.Visualizer.Lines.RotationDegreesZ.ToString();
        }

        public void AddLine(Line2D line)
        {
            if(line.HeadUI != null)
            {
                this.GraphContainer.Children.Add(line.HeadUI);
            }
            if (line.HeadUI2 != null)
            {
                this.GraphContainer.Children.Add(line.HeadUI2);
            }
            this.GraphContainer.Children.Add(line.LineUI);
        }
        public void RemoveLine(Line2D line)
        {
            if (line.HeadUI != null)
            {
                this.GraphContainer.Children.Remove(line.HeadUI);
            }
            if (line.HeadUI2 != null)
            {
                this.GraphContainer.Children.Remove(line.HeadUI2);
            }
            this.GraphContainer.Children.Remove(line.LineUI);
        }

        public void ResetColorIndex()
        {
            throw new NotImplementedException();
        }

        private void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this._isDragging = true;
            this._mouseLastPoint = e.GetPosition(this.GraphContainer);
            this.Visualizer.MouseLeftButtonDown();
        }

        private void Page_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            this.UndoMouseDown();
            this.Visualizer.MouseLeftButtonUp();
        }
        private void Page_MouseLeave(object sender, MouseEventArgs e)
        {
            this.UndoMouseDown();
            this._isOverSliderX = this._isOverSliderY = this._isOverSliderZ = false;
        }

        private void UndoMouseDown()
        {
            this._isDragging = false;   
        }
        

        private void Page_MouseMove(object sender, MouseEventArgs e)
        {
            if(!this._isDragging)
            {
                return;
            }
            var mousePoint = e.GetPosition(this.GraphContainer);
            if (e.GetPosition(this.LayoutRoot).X > 844)
            {
                this._isDragging = false;
                return;
            }
            else
            {
                this._isOverSliderX = this._isOverSliderY = this._isOverSliderZ = false;
            }

            this.Visualizer.MouseMove(
                (mousePoint.X - this._mouseLastPoint.X) * COEF_MOVE,
                (mousePoint.Y - this._mouseLastPoint.Y) * COEF_MOVE
            );
            this._mouseLastPoint = mousePoint;
        }

        private void ResetBtn_Click(object sender, RoutedEventArgs e)
        {
            this.Visualizer.SetInitialPosition();
        }

        private void DegreesX_LostFocus(object sender, RoutedEventArgs e)
        {
            this.VerifyAndSetAxisValue(
                    sender as TextBox,
                    (degrees, visualizer) =>
                    {
                        visualizer.Lines.RotateToDegreesAroundX(degrees);
                        this.Visualizer.Lines.ReDraw();
                        return degrees.ToString();
                    });
        }

        private void DegreesY_LostFocus(object sender, RoutedEventArgs e)
        {
            this.VerifyAndSetAxisValue(
                    sender as TextBox,
                    (degrees, visualizer) =>
                    {
                        visualizer.Lines.RotateToDegreesAroundY(degrees);
                        this.Visualizer.Lines.ReDraw();
                        return degrees.ToString();
                    });
        }

        private void DegreesZ_LostFocus(object sender, RoutedEventArgs e)
        {
            this.VerifyAndSetAxisValue(
                    sender as TextBox,
                    (degrees, visualizer) =>
                    {
                        visualizer.Lines.RotateToDegreesAroundZ(degrees);
                        this.Visualizer.Lines.ReDraw();
                        return degrees.ToString();
                    });
        }

        private void DegreesX_KeyUp(object sender, KeyEventArgs e)
        {
            if(e.Key == Key.Enter)
            {
                this.DegreesX_LostFocus(sender, e);
            }
        }

        private void DegreesY_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                this.DegreesY_LostFocus(sender, e);
            }
        }

        private void DegreesZ_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                this.DegreesZ_LostFocus(sender, e);
            }
        }

        

        private void VerifyAndSetAxisValue(TextBox textBox, Func<double, VectorVisualizer, string> func)
        {
            var text = textBox.Text.Trim().Replace(',', '.');
            if (text == String.Empty)
            {
                textBox.Text = func(0, this.Visualizer);
                textBox.Select(textBox.Text.Length, 0);
                return;
            }
            double degrees;
            if (Double.TryParse(text, out degrees))
            {
                degrees = degrees % 360;
                textBox.Text = func(degrees, this.Visualizer);
                textBox.Select(textBox.Text.Length, 0);
                return;
            }
            HtmlPage.Window.Alert(SR.PleaseEnterNumericValue);
            textBox.Text = func(0, this.Visualizer);
            textBox.Select(textBox.Text.Length, 0);
        }

        private void VerifyVectorValue(TextBox textBox)
        {
            var text = textBox.Text.Trim().Replace(',', '.');
            if (text == "-")
            {
                return;
            }
            if (text == String.Empty)
            {
                textBox.Text = 0.ToString();
                return;
            }
            double value;
            if (Double.TryParse(text, out value))
            {
                if (value < _VectorLimit * -1 || value > _VectorLimit)
                {
                    HtmlPage.Window.Alert(SR.TheValueMustBeBetween.Args(_VectorLimit));
                    textBox.Text = (value > 0 ? _VectorLimit : _VectorLimit*-1).ToString();
                }
                return;
            }
            HtmlPage.Window.Alert(SR.PleaseEnterNumericValue);
            textBox.Text = 0.ToString();
        }

        private void SliderX_MouseEnter(object sender, EventArgs e)
        {
            this._isOverSliderX = true;
        }

        private void SliderY_MouseEnter(object sender, EventArgs e)
        {
            this._isOverSliderY = true;
        }

        private void SliderZ_MouseEnter(object sender, EventArgs e)
        {
            this._isOverSliderZ = true;
        }

        

        private void SliderX_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var slider = (Slider) sender;
            if (!this._isOverSliderX || !slider.IsFocused)
            {
                return;
            }
            this.Visualizer.Lines.ShiftDegreesAroundX(((e.NewValue / 10) * 360 - 180) - this.Visualizer.Lines.RotationDegreesX);
            this.Visualizer.Lines.ReDraw();
        }
        private void SliderY_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var slider = (Slider) sender;
            if (!this._isOverSliderY || !slider.IsFocused)
            {
                return;
            }
            this.Visualizer.Lines.ShiftDegreesAroundY(((e.NewValue / 10) * 360 - 180) - this.Visualizer.Lines.RotationDegreesY);
            this.Visualizer.Lines.ReDraw();
        }
        private void SliderZ_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var slider = (Slider)sender;
            if (!this._isOverSliderZ || !slider.IsFocused)
            {
                return;
            }
            this.Visualizer.Lines.ShiftDegreesAroundZ(((e.NewValue / 10) * 360 - 180) - this.Visualizer.Lines.RotationDegreesZ);
            this.Visualizer.Lines.ReDraw();
        }



        public Brush NextColor
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public void ShowInfo(string info)
        {
            StarDetails.Visibility = Visibility.Visible;
            StarDetails.Text = info;
        }
        public void HideInfo()
        {
            StarDetails.Visibility = Visibility.Collapsed;
        }


        /*
        private void AddStar(double x, double y, double z, double radius, Color color)
        {
            var vector = new VectorUI(_VectorFactor)
            {
                BeginningX = 0,
                BeginningY = 0,
                BeginningZ = 0,
                EndX = x,
                EndY = y,
                EndZ = z,
            };
            if (vector.HasNegativeValues())
            {
               throw new Exception(SR.VectorCannotHaveNegativeValue);
            }
            if (vector.HasValuesExceeding(_VectorLimit))
            {
                throw new Exception(SR.VectorCannotHaveValueBiggerThan.Args(vector, _VectorLimit, _VectorLimit * -1));
            }
            if (this.Visualizer.Vectors.Find((vUI, i) => vUI.Equals(vector)) != null)
            {
                throw new Exception(SR.VectorIsAlreadyDefined.Args(vector));
            }
            vector.HeadUI.Width = vector.HeadUI.Height = radius;
            vector.Stroke = new SolidColorBrush(Color.FromArgb(color.A, (byte)(color.R * 0.4), (byte)(color.G * 0.4), (byte)(color.B * 0.4)));
            vector.Fill = new SolidColorBrush(color);
            this.AddVector(vector);
        }
        
        private void AddVector(VectorUI vector)
        {
            this.Visualizer.AddVector(vector);
        }*/










    }

    
}
